package cn.stazxr.service.impl;

import cn.stazxr.constants.DeleteFlagEnum;
import cn.stazxr.constants.HttpConstant;
import cn.stazxr.core.RedisTemplate;
import cn.stazxr.core.TokenHandler;
import cn.stazxr.dao.YdlUserDao;
import cn.stazxr.entity.YdlLoginUser;
import cn.stazxr.entity.YdlMenu;
import cn.stazxr.entity.YdlRole;
import cn.stazxr.entity.YdlUser;
import cn.stazxr.exception.BusinessException;
import cn.stazxr.exception.PasswordIncorrectException;
import cn.stazxr.exception.UserNotFoundException;
import cn.stazxr.service.YdlUserService;
import cn.stazxr.utils.WebUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.bitwalker.useragentutils.UserAgent;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

import static cn.stazxr.constants.RedisKeyConstant.PERM_PREFIX;
import static cn.stazxr.constants.RedisKeyConstant.ROLE_PREFIX;
import static cn.stazxr.constants.RedisKeyConstant.TOKEN_TIME;

/**
 * 用户信息表(YdlUser)表服务实现类
 *
 * @author makejava
 * @since 2025-10-28 22:51:59
 */
@Slf4j
@Service("ydlUserService")
public class YdlUserServiceImpl implements YdlUserService {

	@Autowired
	private YdlUserDao ydlUserDao;
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private TokenHandler tokenHandler;
	@Autowired
	private RedisTemplate redisTemplate;

	/**
	 * 通过ID查询单条数据
	 *
	 * @param userId 主键
	 * @return 实例对象
	 */
	@Override
	public YdlUser queryById(Long userId) {
		return this.ydlUserDao.queryById(userId);
	}

	/**
	 * 分页查询
	 *
	 * @param ydlUser     筛选条件
	 * @param pageRequest 分页对象
	 * @return 查询结果
	 */
	@Override
	public Page<YdlUser> queryByPage(YdlUser ydlUser, PageRequest pageRequest) {
		if (ydlUser.getUserName() != null && !ydlUser.getUserName().isEmpty()) {
			ydlUser.setUserName("%" + ydlUser.getUserName() + "%");
		}
		if (ydlUser.getNickName() != null && !ydlUser.getNickName().isEmpty()) {
			ydlUser.setNickName("%" + ydlUser.getNickName() + "%");
		}
		long total = this.ydlUserDao.count(ydlUser);
		return new PageImpl<>(this.ydlUserDao.queryAllByLimit(ydlUser, pageRequest), pageRequest, total);
	}

	/**
	 * 新增数据
	 *
	 * @param ydlUser 实例对象
	 * @return 实例对象
	 */
	@Override
	public YdlUser insert(YdlUser ydlUser) {
		this.ydlUserDao.insert(ydlUser);
		return ydlUser;
	}

	/**
	 * 修改数据
	 *
	 * @param ydlUser 实例对象
	 * @return 实例对象
	 */
	@Override
	public YdlUser update(YdlUser ydlUser) {
		this.ydlUserDao.update(ydlUser);
		return this.queryById(ydlUser.getUserId());
	}

	/**
	 * 通过主键删除数据
	 *
	 * @param userId 主键
	 * @return 是否成功
	 */
	@Override
	public boolean deleteById(Long userId) {
		String userName = Objects.requireNonNull(WebUtils.getCurrentRequest()).getHeader("userName");
		YdlUser ydlUser = new YdlUser();
		Date date = new Date();
		ydlUser.setUpdateTime(date);
		ydlUser.setUpdateBy(userName);
		ydlUser.setUserId(userId);
		ydlUser.setDelFlag(DeleteFlagEnum.YES.getValue());
		ydlUser.setStatus(DeleteFlagEnum.YES.getValue());
		return this.ydlUserDao.update(ydlUser) > 0;
	}

	@Override
	public YdlLoginUser login(String userName, String password) throws JsonProcessingException {
		// 1、登录，使用用户名查询用户，没有查到，说明用户不存在
		YdlUser ydlUser = ydlUserDao.queryByUserName(userName);
		if (ydlUser == null) {
			throw new UserNotFoundException("执行登录操作：[" + userName + "] 用户不存在");
		}
		// 2、查到用户，验证密码是否正确
		if (!password.equals(ydlUser.getPassword())) {
			throw new PasswordIncorrectException("执行登录操作：[" + userName + "] 用户密码错误");
		}
		// 3、密码正确，返回登录用户信息
		// 1）生成token
		String token = UUID.randomUUID().toString();
		HttpServletRequest request = Objects.requireNonNull(WebUtils.getCurrentRequest());
		UserAgent userAgent = new UserAgent(request.getHeader("User-Agent"));

		// 通过ip获取其所属的地址
		ResponseEntity<String> result = restTemplate.getForEntity("https://whois.pconline.com.cn/ipJson.jsp?ip=" + request.getRemoteHost() + "&json=true", String.class);
		String body = result.getBody();
		Map<String, String> map = objectMapper.readValue(body, new TypeReference<>() {});

		String location = map.get("addr") + map.get("pro") + map.get("city") + map.get("region");
		// 2）封装返回前端数据，保存到Redis
		YdlLoginUser ydlLoginUser = YdlLoginUser.builder()
			.userId(ydlUser.getUserId())
			.token(token)
			.ipaddr(request.getRemoteAddr())
			.loginTime(Instant.now())
			.os(userAgent.getOperatingSystem().getName())
			.browser(userAgent.getBrowser().getName())
			.loginLocation(location)
			.ydlUser(ydlUser).build();
		tokenHandler.saveToken(token, ydlLoginUser);
		return ydlLoginUser;
	}

	@Override
	public void logout() throws BusinessException {
		HttpServletRequest request = Objects.requireNonNull(WebUtils.getCurrentRequest());
		String token = request.getHeader(HttpConstant.AUTHORIZATION);
		String userName = request.getHeader("UserName");
		tokenHandler.deleteToken(token, userName);
	}

	@Override
	public Map<String, List<String>> getInfo() {
		YdlLoginUser ydlLoginUser = getLoginUser();
		if (ydlLoginUser == null) {
			throw new BusinessException("用户未登录");
		}
		YdlUser info = ydlUserDao.getInfo(ydlLoginUser.getUserId());
		// 处理权限和角色的关系
		// （1）roles:token: [admin,xxx,yyy] perms:token: [system:user:add,system:user:update]
		List<String> roleTags = info.getYdlRoles().stream()
			.map(YdlRole::getRoleTag)
			.filter(Objects::nonNull)
			.toList();
		redisTemplate.setObject(ROLE_PREFIX + ydlLoginUser.getToken(), TOKEN_TIME, roleTags);
		List<String> perms = new ArrayList<>();
		// [{roleName:cc,roleTag:xxx,perms:[{id:'xxx',perm:'system'}]}]
		info.getYdlRoles().stream()
			.map(YdlRole::getYdlMenus)
			.filter(Objects::nonNull)
			.forEach(menus -> perms.addAll(
				menus.stream()
					.map(YdlMenu::getPerms)
					.filter(Objects::nonNull)
					.toList()));
		redisTemplate.setObject(PERM_PREFIX + ydlLoginUser.getToken(), TOKEN_TIME, perms);
		// 整合数据
		HashMap<String, List<String>> data = new HashMap<>();
		data.put("roles", roleTags);
		data.put("perms", perms);
		return data;
	}

	private YdlLoginUser getLoginUser() {
		HttpServletRequest request = Objects.requireNonNull(WebUtils.getCurrentRequest());
		String token = request.getHeader(HttpConstant.AUTHORIZATION);
		String userName = request.getHeader("userName");
		if (token == null) {
			throw new BusinessException("未登录");
		}
		// 3. 使用token去 Redis 中查询用户信息
		return tokenHandler.getYdlLoginUser(token, userName);
	}

//
//	public static void main(String[] args) throws JsonProcessingException {
//		// 使用java发送HTTP请求
//		RestTemplate restTemplate = new RestTemplate();
//		ResponseEntity<String> result = restTemplate.getForEntity("https://whois.pconline.com.cn/ipJson.jsp?ip=122.66.55.233&json=true", String.class);
//		System.out.println(result);
//		// 通过ip获取其所属的地址
//		String body = result.getBody();
//		ObjectMapper objectMapper = new ObjectMapper();
//		Map<String, String> map = objectMapper.readValue(body, new TypeReference<>() {});
//		String location = map.get("addr") + map.get("pro") + map.get("city") + map.get("region");
//		System.out.println(location);
//	}
}
